// Copyright Epic Games, Inc. All Rights Reserved.

#include "GameFeatureAction_AddInputContextMapping.h"
#include "Components/GameFrameworkComponentManager.h"
#include "Engine/GameInstance.h"
#include "GameFramework/PlayerController.h"
#include "Engine/LocalPlayer.h"
#include "Engine/World.h"
#include "EnhancedInputSubsystems.h"
#include "GameFeatures/GameFeatureAction_WorldActionBase.h"
#include "InputMappingContext.h"
#include "Character/LyraHeroComponent.h"
#include "UserSettings/EnhancedInputUserSettings.h"
#include "System/LyraAssetManager.h"

#if WITH_EDITOR
#include "Misc/DataValidation.h" // 数据验证相关
#endif

#include UE_INLINE_GENERATED_CPP_BY_NAME(GameFeatureAction_AddInputContextMapping) // 包含自动生成的代码

#define LOCTEXT_NAMESPACE "GameFeatures" // 定义本地化文本命名空间

//////////////////////////////////////////////////////////////////////
// UGameFeatureAction_AddInputContextMapping

/**
 * 游戏特性注册时调用
 */
void UGameFeatureAction_AddInputContextMapping::OnGameFeatureRegistering()
{
	Super::OnGameFeatureRegistering(); // 调用父类方法

	RegisterInputMappingContexts(); // 注册输入映射上下文
}

/**
 * 游戏特性激活时调用
 */
void UGameFeatureAction_AddInputContextMapping::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
{
	FPerContextData& ActiveData = ContextData.FindOrAdd(Context); // 查找或添加上下文数据
	if (!ensure(ActiveData.ExtensionRequestHandles.IsEmpty()) || // 确保扩展请求句柄为空
		!ensure(ActiveData.ControllersAddedTo.IsEmpty())) // 确保ControllersAddedTo为空
	{
		Reset(ActiveData); // 重置数据
	}
	Super::OnGameFeatureActivating(Context); // 调用父类方法
}

/**
 * 游戏特性停用时调用
 */
void UGameFeatureAction_AddInputContextMapping::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
	Super::OnGameFeatureDeactivating(Context); // 调用父类方法

	FPerContextData* ActiveData = ContextData.Find(Context); // 查找上下文数据
	if (ensure(ActiveData)) // 确保数据有效
	{
		Reset(*ActiveData); // 重置数据
	}
}

/**
 * 游戏特性取消注册时调用
 */
void UGameFeatureAction_AddInputContextMapping::OnGameFeatureUnregistering()
{
	Super::OnGameFeatureUnregistering();	// 调用父类方法
	
	UnregisterInputMappingContexts(); // 取消注册输入映射上下文
}

/**
 * 注册输入映射上下文的方法
 */
void UGameFeatureAction_AddInputContextMapping::RegisterInputMappingContexts()
{
	RegisterInputContextMappingsForGameInstanceHandle = FWorldDelegates::OnStartGameInstance.AddUObject(this, &UGameFeatureAction_AddInputContextMapping::RegisterInputContextMappingsForGameInstance); // 绑定游戏实例开始委托

	const TIndirectArray<FWorldContext>& WorldContexts = GEngine->GetWorldContexts(); // 获取世界上下文数组
	for (TIndirectArray<FWorldContext>::TConstIterator WorldContextIterator = WorldContexts.CreateConstIterator(); WorldContextIterator; ++WorldContextIterator) // 遍历世界上下文
	{
		RegisterInputContextMappingsForGameInstance(WorldContextIterator->OwningGameInstance); // 为游戏实例注册输入上下文映射
	}
}

/**
 * 为游戏实例注册输入上下文映射的方法
 */
void UGameFeatureAction_AddInputContextMapping::RegisterInputContextMappingsForGameInstance(UGameInstance* GameInstance)
{
	if (GameInstance != nullptr && !GameInstance->OnLocalPlayerAddedEvent.IsBoundToObject(this)) // 检查游戏实例有效且未绑定事件
	{
		GameInstance->OnLocalPlayerAddedEvent.AddUObject(this, &UGameFeatureAction_AddInputContextMapping::RegisterInputMappingContextsForLocalPlayer); // 绑定本地玩家添加事件
		GameInstance->OnLocalPlayerRemovedEvent.AddUObject(this, &UGameFeatureAction_AddInputContextMapping::UnregisterInputMappingContextsForLocalPlayer); // 绑定本地玩家移除事件
		
		for (TArray<ULocalPlayer*>::TConstIterator LocalPlayerIterator = GameInstance->GetLocalPlayerIterator(); LocalPlayerIterator; ++LocalPlayerIterator) // 遍历本地玩家
		{
			RegisterInputMappingContextsForLocalPlayer(*LocalPlayerIterator); // 为本地玩家注册输入映射上下文
		}
	}
}

/**
 * 为本地玩家注册输入映射上下文的方法
 */
void UGameFeatureAction_AddInputContextMapping::RegisterInputMappingContextsForLocalPlayer(ULocalPlayer* LocalPlayer)
{
	if (ensure(LocalPlayer)) // 确保本地玩家有效
	{
		ULyraAssetManager& AssetManager = ULyraAssetManager::Get(); // 获取资源管理器
		
		if (UEnhancedInputLocalPlayerSubsystem* EISubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LocalPlayer)) // 获取增强输入子系统
		{
			if (UEnhancedInputUserSettings* Settings = EISubsystem->GetUserSettings()) // 获取用户设置
			{
				for (const FInputMappingContextAndPriority& Entry : InputMappings) // 遍历输入映射
				{
					// 跳过不想注册的条目
					if (!Entry.bRegisterWithSettings) // 检查是否要注册到设置
					{
						continue; // 跳过
					}

					// 将此IMC注册到设置！
					if (UInputMappingContext* IMC = AssetManager.GetAsset(Entry.InputMapping)) // 获取输入映射上下文
					{
						Settings->RegisterInputMappingContext(IMC); // 注册输入映射上下文
					}
				}
			}
		}
	}
}

/**
 * 取消注册输入映射上下文的方法
 */
void UGameFeatureAction_AddInputContextMapping::UnregisterInputMappingContexts()
{
	FWorldDelegates::OnStartGameInstance.Remove(RegisterInputContextMappingsForGameInstanceHandle); // 移除游戏实例开始委托
	RegisterInputContextMappingsForGameInstanceHandle.Reset(); // 重置委托句柄

	const TIndirectArray<FWorldContext>& WorldContexts = GEngine->GetWorldContexts(); // 获取世界上下文数组
	for (TIndirectArray<FWorldContext>::TConstIterator WorldContextIterator = WorldContexts.CreateConstIterator(); WorldContextIterator; ++WorldContextIterator) // 遍历世界上下文
	{
		UnregisterInputContextMappingsForGameInstance(WorldContextIterator->OwningGameInstance); // 为游戏实例取消注册输入上下文映射
	}
}

/**
 * 为游戏实例取消注册输入上下文映射的方法
 */
void UGameFeatureAction_AddInputContextMapping::UnregisterInputContextMappingsForGameInstance(UGameInstance* GameInstance)
{
	if (GameInstance != nullptr) // 检查游戏实例有效
	{
		GameInstance->OnLocalPlayerAddedEvent.RemoveAll(this); // 移除所有本地玩家添加事件
		GameInstance->OnLocalPlayerRemovedEvent.RemoveAll(this); // 移除所有本地玩家移除事件

		for (TArray<ULocalPlayer*>::TConstIterator LocalPlayerIterator = GameInstance->GetLocalPlayerIterator(); LocalPlayerIterator; ++LocalPlayerIterator) // 遍历本地玩家
		{
			UnregisterInputMappingContextsForLocalPlayer(*LocalPlayerIterator); // 为本地玩家取消注册输入映射上下文
		}
	}
}

/**
 * 为本地玩家取消注册输入映射上下文的方法
 */
void UGameFeatureAction_AddInputContextMapping::UnregisterInputMappingContextsForLocalPlayer(ULocalPlayer* LocalPlayer)
{
	if (ensure(LocalPlayer)) // 确保本地玩家有效
	{
		if (UEnhancedInputLocalPlayerSubsystem* EISubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LocalPlayer)) // 获取增强输入子系统
		{
			if (UEnhancedInputUserSettings* Settings = EISubsystem->GetUserSettings()) // 获取用户设置
			{
				for (const FInputMappingContextAndPriority& Entry : InputMappings) // 遍历输入映射
				{
					// 跳过不想注册的条目
					if (!Entry.bRegisterWithSettings) // 检查是否要注册到设置
					{
						continue; // 跳过
					}

					// 从设置中取消注册此IMC！
					if (UInputMappingContext* IMC = Entry.InputMapping.Get()) // 获取输入映射上下文
					{
						Settings->UnregisterInputMappingContext(IMC); // 取消注册输入映射上下文
					}
				}
			}
		}
	}
}


#if WITH_EDITOR
/**
 * 数据验证方法
 */
EDataValidationResult UGameFeatureAction_AddInputContextMapping::IsDataValid(FDataValidationContext& Context) const
{
	EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(Context), EDataValidationResult::Valid); // 组合数据验证结果

	int32 Index = 0; // 索引

	for (const FInputMappingContextAndPriority& Entry : InputMappings) // 遍历输入映射
	{
		if (Entry.InputMapping.IsNull()) // 检查输入映射是否为空
		{
			Result = EDataValidationResult::Invalid; // 设置为无效
			Context.AddError(FText::Format(LOCTEXT("NullInputMapping", "索引{0}处的InputMapping为空。"), Index)); // 添加错误信息
		}
		++Index; // 递增索引
	}

	return Result; // 返回结果
}
#endif

/**
 * 添加到世界的方法
 */
void UGameFeatureAction_AddInputContextMapping::AddToWorld(const FWorldContext& WorldContext, const FGameFeatureStateChangeContext& ChangeContext)
{
	UWorld* World = WorldContext.World(); // 获取世界
	UGameInstance* GameInstance = WorldContext.OwningGameInstance; // 获取游戏实例
	FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); // 查找或添加上下文数据

	if ((GameInstance != nullptr) && (World != nullptr) && World->IsGameWorld()) // 检查游戏实例和世界是否有效
	{
		if (UGameFrameworkComponentManager* ComponentManager = UGameInstance::GetSubsystem<UGameFrameworkComponentManager>(GameInstance)) // 获取组件管理器
		{
			UGameFrameworkComponentManager::FExtensionHandlerDelegate AddAbilitiesDelegate = // 创建扩展处理委托
				UGameFrameworkComponentManager::FExtensionHandlerDelegate::CreateUObject(this, &ThisClass::HandleControllerExtension, ChangeContext); // 绑定到处理函数
			TSharedPtr<FComponentRequestHandle> ExtensionRequestHandle = // 创建扩展请求句柄
				ComponentManager->AddExtensionHandler(APlayerController::StaticClass(), AddAbilitiesDelegate); // 添加扩展处理器

			ActiveData.ExtensionRequestHandles.Add(ExtensionRequestHandle); // 添加扩展请求句柄
		}
	}
}

/**
 * 重置数据的方法
 */
void UGameFeatureAction_AddInputContextMapping::Reset(FPerContextData& ActiveData)
{
	ActiveData.ExtensionRequestHandles.Empty(); // 清空扩展请求句柄

	while (!ActiveData.ControllersAddedTo.IsEmpty()) // 当ControllersAddedTo不为空时
	{
		TWeakObjectPtr<APlayerController> ControllerPtr = ActiveData.ControllersAddedTo.Top(); // 获取顶部控制器指针
		if (ControllerPtr.IsValid()) // 检查控制器指针有效
		{
			RemoveInputMapping(ControllerPtr.Get(), ActiveData); // 移除输入映射
		}
		else
		{
			ActiveData.ControllersAddedTo.Pop(); // 弹出无效指针
		}
	}
}

/**
 * 处理控制器扩展的方法
 */
void UGameFeatureAction_AddInputContextMapping::HandleControllerExtension(AActor* Actor, FName EventName, FGameFeatureStateChangeContext ChangeContext)
{
	APlayerController* AsController = CastChecked<APlayerController>(Actor); // 转换为玩家控制器
	FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); // 查找或添加上下文数据

	// TODO 为什么这段代码混合使用控制器和本地玩家？ControllersAddedTo从未被修改
	if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionRemoved) || (EventName == UGameFrameworkComponentManager::NAME_ReceiverRemoved)) // 检查是否是移除事件
	{
		RemoveInputMapping(AsController, ActiveData); // 移除输入映射
	}
	else if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded) || (EventName == ULyraHeroComponent::NAME_BindInputsNow)) // 检查是否是添加事件
	{
		AddInputMappingForPlayer(AsController->GetLocalPlayer(), ActiveData); // 为玩家添加输入映射
	}
}

/**
 * 为玩家添加输入映射的方法
 */
void UGameFeatureAction_AddInputContextMapping::AddInputMappingForPlayer(UPlayer* Player, FPerContextData& ActiveData)
{
	if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(Player)) // 转换为本地玩家
	{
		if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) // 获取增强输入子系统
		{
			for (const FInputMappingContextAndPriority& Entry : InputMappings) // 遍历输入映射
			{
				if (const UInputMappingContext* IMC = Entry.InputMapping.Get()) // 获取输入映射上下文
				{
					InputSystem->AddMappingContext(IMC, Entry.Priority); // 添加映射上下文
				}
			}
		}
		else
		{
			UE_LOG(LogGameFeatures, Error, TEXT("未能找到本地玩家的`UEnhancedInputLocalPlayerSubsystem`。输入映射将不会被添加。请确保通过配置文件设置为使用EnhancedInput系统。")); // 记录错误日志
		}
	}
}

/**
 * 移除输入映射的方法
 */
void UGameFeatureAction_AddInputContextMapping::RemoveInputMapping(APlayerController* PlayerController, FPerContextData& ActiveData)
{
	if (ULocalPlayer* LocalPlayer = PlayerController->GetLocalPlayer()) // 获取本地玩家
	{
		if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) // 获取增强输入子系统
		{
			for (const FInputMappingContextAndPriority& Entry : InputMappings) // 遍历输入映射
			{
				if (const UInputMappingContext* IMC = Entry.InputMapping.Get()) // 获取输入映射上下文
				{
					InputSystem->RemoveMappingContext(IMC); // 移除映射上下文
				}
			}
		}
	}

	ActiveData.ControllersAddedTo.Remove(PlayerController); // 从列表中移除控制器
}

#undef LOCTEXT_NAMESPACE // 取消定义本地化文本命名空间